Header file reference.hpp

namespace type_safe
{
    template <typename T, bool XValue>
    class object_ref;
    
    template <typename T, bool XValue>
    struct optional_storage_policy_for<object_ref<T, XValue>>;
    
    //=== Object reference comparison ===//
    template <typename T, typename U, bool XValue>
    constexpr )>bool operator==(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;
    template <typename T, typename U, bool XValue>
    constexpr )>bool operator==(const object_ref<T, XValue>& a, U& b) noexcept;
    template <typename T, typename U, bool XValue>
    constexpr )>bool operator==(const T& a, const object_ref<U, XValue>& b) noexcept;
    template <typename T, typename U, bool XValue>
    constexpr )>bool operator!=(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;
    template <typename T, typename U, bool XValue>
    constexpr )>bool operator!=(const object_ref<T, XValue>& a, U& b) noexcept;
    template <typename T, typename U, bool XValue>
    constexpr )>bool operator!=(const T& a, const object_ref<U, XValue>& b) noexcept;
    
    template <typename T, bool XValue, typename Func, typename ... Args>
    void with(const object_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);
    
    template <typename T>
    constexpr object_ref<T> ref(T& obj) noexcept;
    template <typename T>
    constexpr object_ref<const T> cref(const T& obj) noexcept;
    
    template <typename T>
    using xvalue_ref = object_ref<T, true>;
    
    template <typename T>
    constexpr xvalue_ref<T> xref(T& obj) noexcept;
    
    template <typename T>
    constexpr typename std::remove_const<T>::type copy(const object_ref<T>& obj);
    template <typename T>
    constexpr T move(const xvalue_ref<T>& obj) noexcept('hidden');
    
    template <typename T, bool XValue = false>
    class array_ref;
    
    template <typename T, bool XValue, typename Func, typename ... Args>
    void with(const array_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);
    
    template <typename T, std::size_t Size>
    array_ref<T> ref(T(&)[Size] arr) noexcept;
    template <typename T>
    array_ref<T> ref(T* begin, T* end) noexcept;
    template <typename T>
    array_ref<T> ref(T* array, size_t size) noexcept;
    
    template <typename T, std::size_t Size>
    array_ref<const T> cref(const T(&)[Size] arr) noexcept;
    template <typename T>
    array_ref<const T> cref(const T* begin, const T* end) noexcept;
    template <typename T>
    array_ref<const T> cref(const T* array, size_t size) noexcept;
    
    template <typename T>
    using array_xvalue_ref = array_ref<T, true>;
    
    template <typename T, std::size_t Size>
    array_xvalue_ref<T> xref(T(&)[Size] arr) noexcept;
    template <typename T>
    array_xvalue_ref<T> xref(T* begin, T* end) noexcept;
    template <typename T>
    array_xvalue_ref<T> xref(T* array, size_t size) noexcept;
    
    template <typename Return, typename ... Args>
    class function_ref<Return(Args...)>;
}

Class template type_safe::object_ref

template <typename T, bool XValue>
class object_ref
{
public:
    using value_type = T;
    
    using reference_type = typename std::conditional<XValue, T&&, T&>::type;
    
    template <typename U>
    )>object_ref& operator=(const object_ref<U>& obj) noexcept;
    
    constexpr reference_type get() const noexcept;
    constexpr reference_type operator*() const noexcept;
    
    constexpr T* operator->() const noexcept;
    
    template <typename Func, typename ... Args>
    'hidden' map(Func&& f, Args&&... args);
};

A reference to an object of some type T.

Unlike std::reference_wrapper it does not try to model reference semantics, instead it is basically a non-null pointer to a single object. This allows rebinding on assignment. Apart from the different access syntax it can be safely used instead of a reference, and is safe for all kinds of containers.

If the given type is const, it will only return a const reference, but then XValue must be false.

If XValue is true, dereferencing will std::move() the object, modelling a reference to an expiring lvalue.

Notes: T is the type without the reference, ie. object_ref<int>.

Assignment operator type_safe::object_ref::operator=

(1)  template <typename U>
     )>object_ref& operator=(const object_ref<U>& obj) noexcept;

Function type_safe::object_ref::get

(1)  constexpr reference_type get() const noexcept;

(2)  constexpr reference_type operator*() const noexcept;

Returns: A native reference to the referenced object. if XValue is true, this will be an rvalue reference, else an lvalue reference.

Operator type_safe::object_ref::operator->

constexpr T* operator->() const noexcept;

Member access operator.

Function template type_safe::object_ref::map

template <typename Func, typename ... Args>
'hidden' map(Func&& f, Args&&... args);

Effects: Invokes the function with the referred object followed by the arguments.

Returns: A ts::object_ref to the result of the function, if *this is an xvalue reference, the result is as well.

Requires: The function must return an lvalue or another ts::object_ref object.


Class template type_safe::optional_storage_policy_for<object_ref<T, XValue>> [optional]

template <typename T, bool XValue>
struct optional_storage_policy_for<object_ref<T, XValue>>
{
    using type = reference_optional_storage<T, XValue>;
};

Sets the ts::basic_optional storage policy for ts::object_ref to ts::reference_optional_storage.

It will be used when the optional is rebound.

Object reference comparison

(1)  template <typename T, typename U, bool XValue>
     constexpr )>bool operator==(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;

(2)  template <typename T, typename U, bool XValue>
     constexpr )>bool operator==(const object_ref<T, XValue>& a, U& b) noexcept;

(3)  template <typename T, typename U, bool XValue>
     constexpr )>bool operator==(const T& a, const object_ref<U, XValue>& b) noexcept;

(4)  template <typename T, typename U, bool XValue>
     constexpr )>bool operator!=(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;

(5)  template <typename T, typename U, bool XValue>
     constexpr )>bool operator!=(const object_ref<T, XValue>& a, U& b) noexcept;

(6)  template <typename T, typename U, bool XValue>
     constexpr )>bool operator!=(const T& a, const object_ref<U, XValue>& b) noexcept;

Comparison operator for ts::object_ref.

Two references are equal if both refer to the same object. A reference is equal to an object if the reference refers to that object.

Notes: These functions do not participate in overload resolution if the types are not compatible (i.e. const/non-const or derived).

Function template type_safe::with

template <typename T, bool XValue, typename Func, typename ... Args>
void with(const object_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);

With operation for ts::object_ref.

Effects: Calls the operator() of f passing it *ref and the additional arguments.

Function template type_safe::ref

(1)  template <typename T>
     constexpr object_ref<T> ref(T& obj) noexcept;

(2)  template <typename T>
     constexpr object_ref<const T> cref(const T& obj) noexcept;

Creates a (const) ts::object_ref.

Returns: A ts::object_ref to the given object.

Alias template type_safe::xvalue_ref

template <typename T>
using xvalue_ref = object_ref<T, true>;

Convenience alias of ts::object_ref where XValue is true.

Function template type_safe::xref

template <typename T>
constexpr xvalue_ref<T> xref(T& obj) noexcept;

Creates a ts::xvalue_ref.

Returns: A ts::xvalue_ref to the given object.

Function template type_safe::copy

(1)  template <typename T>
     constexpr typename std::remove_const<T>::type copy(const object_ref<T>& obj);

(2)  template <typename T>
     constexpr T move(const xvalue_ref<T>& obj) noexcept('hidden');

Returns: A new object containing a copy of the referenced object. It will use the copy (1)/move constructor (2).

Throws: Anything thrown by the copy (1)/move (2) constructor.

Class template type_safe::array_ref

template <typename T, bool XValue = false>
class array_ref
{
public:
    using value_type = T;
    
    using reference_type = typename std::conditional<XValue, T&&, T&>::type;
    
    using iterator = T*;
    
    array_ref(std::nullptr_t);
    void assign(std::nullptr_t) noexcept;
    
    array_ref(T* begin, T* end) noexcept;
    void assign(T* begin, T* end) noexcept;
    
    array_ref(T* array, size_t size) noexcept;
    void assign(T* array, size_t size) noexcept;
    
    template <std::size_t Size>
    array_ref(T(&)[Size] arr);
    template <std::size_t Size>
    void assign(T(&)[Size] arr) noexcept;
    
    iterator begin() const noexcept;
    
    iterator end() const noexcept;
    
    T* data() const noexcept;
    
    size_t size() const noexcept;
    
    reference_type operator[](index_t i) const noexcept;
};

A reference to an array of objects of type T.

It is a simple pointer + size pair that allows reference access to each element in the array. An "array" here is any contiguous storage (so C arrays, std::vector, etc.). It does not allow changing the size of the array, only the individual elements. Like ts::object_ref it can be safely used in containers.

If the given type is const, it will only return a const reference to each element, but then XValue must be false.

If XValue is true, dereferencing will std::move() the object, modelling a reference to an expiring lvalue.

Notes: T is the type stored in the array, so array_ref<int> to reference a contiguous storage of ints. \notes Unlike the other types it isn't technically non-null, as it may contain an empty array. But the range [data(), data() + size) will always be valid.

Constructor type_safe::array_ref::array_ref

(1)  array_ref(std::nullptr_t);

(2)  void assign(std::nullptr_t) noexcept;

Effects: Sets the reference to an empty array.

Constructor type_safe::array_ref::array_ref

(1)  array_ref(T* begin, T* end) noexcept;

(2)  void assign(T* begin, T* end) noexcept;

Effects: Sets the reference to the memory range [begin, end).

Requires: begin <= end.

Constructor type_safe::array_ref::array_ref

(1)  array_ref(T* array, size_t size) noexcept;

(2)  void assign(T* array, size_t size) noexcept;

Effects: Sets the reference to the memory range [array, array + size).

Requires: array must not be nullptr unless size is 0.

Function template type_safe::array_ref::array_ref

(1)  template <std::size_t Size>
     array_ref(T(&)[Size] arr);

(2)  template <std::size_t Size>
     void assign(T(&)[Size] arr) noexcept;

Effects: Sets the reference to the C array.

Function type_safe::array_ref::begin

iterator begin() const noexcept;

Returns: An iterator to the beginning of the array.

Function type_safe::array_ref::end

iterator end() const noexcept;

Returns: An iterator one past the last element of the array.

Function type_safe::array_ref::data

T* data() const noexcept;

Returns: A pointer to the beginning of the array. If size() isn't zero, the pointer is guaranteed to be non-null.

Function type_safe::array_ref::size

size_t size() const noexcept;

Returns: The number of elements in the array.

Array subscript operator type_safe::array_ref::operator[]

reference_type operator[](index_t i) const noexcept;

Returns: A (rvalue if Xvalue is true) reference to the ith element of the array.

Requires: i < size().


Function template type_safe::with

template <typename T, bool XValue, typename Func, typename ... Args>
void with(const array_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);

With operation for ts::array_ref.

Effects: For every element of the array in order, it will invoke f, passing it the current element and the additional arguments. / If XValue is true, it will pass an rvalue reference to the element, allowing it to be moved from.

Function template type_safe::ref

(1)  template <typename T, std::size_t Size>
     array_ref<T> ref(T(&)[Size] arr) noexcept;

(2)  template <typename T>
     array_ref<T> ref(T* begin, T* end) noexcept;

(3)  template <typename T>
     array_ref<T> ref(T* array, size_t size) noexcept;

Creates a ts::array_ref.

Returns: The reference created by forwarding the parameter(s) to the constructor.

Function template type_safe::cref

(1)  template <typename T, std::size_t Size>
     array_ref<const T> cref(const T(&)[Size] arr) noexcept;

(2)  template <typename T>
     array_ref<const T> cref(const T* begin, const T* end) noexcept;

(3)  template <typename T>
     array_ref<const T> cref(const T* array, size_t size) noexcept;

Creates a ts::array_ref to const.

Returns: The reference created by forwarding the parameter(s) to the constructor.

Alias template type_safe::array_xvalue_ref

template <typename T>
using array_xvalue_ref = array_ref<T, true>;

Convenience alias for ts::array_ref where XValue is true.

Function template type_safe::xref

(1)  template <typename T, std::size_t Size>
     array_xvalue_ref<T> xref(T(&)[Size] arr) noexcept;

(2)  template <typename T>
     array_xvalue_ref<T> xref(T* begin, T* end) noexcept;

(3)  template <typename T>
     array_xvalue_ref<T> xref(T* array, size_t size) noexcept;

Creates a ts::array_xvalue_ref.

Returns: The reference created by forwarding the parameter(s) to the constructor.

Class template type_safe::function_ref<Return(Args...)>

template <typename Return, typename ... Args>
class function_ref<Return(Args...)>
{
public:
    using signature = Return(Args...);
    
    function_ref(Return(*)(Args...) fptr);
    
    template <typename Return2, typename ... Args2>
    function_ref(Return2(*)(Args2...) fptr);
    
    template <typename Functor>
    function_ref(const Functor& f);
    
    template <typename Functor>
    function_ref(Functor& f);
    
    template <typename Return2, typename ... Args2>
    function_ref(const function_ref<Return2(Args2...)>& other, 'hidden' = 0);
    
    template <typename Functor>
    void assign(Functor&& f) noexcept;
    
    Return operator()(Args... args) const;
};

A reference to a function.

This is a lightweight reference to a function. It can refer to any function that is compatible with given signature.

A function is compatible if it is callable with regular function call syntax from the given argument types, and its return type is either implicitly convertible to the specified return type or the specified return type is void.

In general it will store a pointer to the functor, requiring an lvalue. But if it is created with a function pointer or something convertible to a function pointer, it will store the function pointer itself. This allows creating it from stateless lambdas.

Notes: Due to implementation reasons, it does not support member function pointers, as it requires regular function call syntax. Create a reference to the object returned by std::mem_fn, if that is required.

Constructor type_safe::function_ref<Return(Args...)>::function_ref

function_ref(Return(*)(Args...) fptr);

Effects: Creates a reference to the function specified by the function pointer.

Requires: fptr must not be nullptr.

Notes: (2) only participates in overload resolution if the type of the function is compatible with the specified signature. \group function_ptr_ctor

Function template type_safe::function_ref<Return(Args...)>::function_ref

(1)  template <typename Return2, typename ... Args2>
     function_ref(Return2(*)(Args2...) fptr);

Function template type_safe::function_ref<Return(Args...)>::function_ref

template <typename Functor>
function_ref(const Functor& f);

Effects: Creates a reference to the function created by the stateless lambda.

Notes: This constructor is intended for stateless lambdas, which are implicitly convertible to function pointers. It does not participate in overload resolution, unless the type is implicitly convertible to a function pointer that is compatible with the specified signature.

Notes: Due to to implementation reasons, it does not work for polymorphic lambdas, it needs an explicit cast to the desired function pointer type. A polymorphic lambda convertible to a direct match function pointer, works however.

Function template type_safe::function_ref<Return(Args...)>::function_ref

template <typename Functor>
function_ref(Functor& f);

Effects: Creates a reference to the specified functor. It will store a pointer to the function object, so it must live as long as the reference.

Notes: This constructor does not participate in overload resolution, unless the functor is compatible with the specified signature.

Function template type_safe::function_ref<Return(Args...)>::function_ref

template <typename Return2, typename ... Args2>
function_ref(const function_ref<Return2(Args2...)>& other, 'hidden' = 0);

Converting copy constructor.

Effects: Creates a reference to the same function referred by other.

Notes: This constructor does not participate in overload resolution, unless the signature of other is compatible with the specified signature.

Notes: This constructor may create a bigger conversion chain. For example, if other has signature void(const char*) it can refer to a function taking std::string. If this signature than accepts a type T implicitly convertible to const char*, calling this will call the function taking std::string, converting T -> std::string, even though such a conversion would be ill-formed otherwise. \param 1 \exclude

Function template type_safe::function_ref<Return(Args...)>::assign

template <typename Functor>
void assign(Functor&& f) noexcept;

Effects: Rebinds the reference to the specified functor.

Notes: This assignment operator only participates in overload resolution, if the argument can also be a valid constructor argument.

Function call operator type_safe::function_ref<Return(Args...)>::operator()

Return operator()(Args... args) const;

Effects: Invokes the stored function with the specified arguments and returns the result.